home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / TCPHDR.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-09-01  |  4.2 KB  |  163 lines

  1. /* TCP header conversion routines
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4. #include "global.h"
  5. #include "mbuf.h"
  6. #include "tcp.h"
  7.  
  8. #if !defined(_lint)
  9. static char rcsid[] OPTIONAL = "$Id: tcphdr.c,v 1.9 1996/09/01 17:09:50 root Exp root $";
  10. #endif
  11.  
  12.  
  13. /* Convert TCP header in host format into mbuf ready for transmission,
  14.  * link in data (if any). If ph != NULL, compute checksum, otherwise
  15.  * take checksum from tcph->checksum
  16.  */
  17. struct mbuf *
  18. htontcp (tcph, data, ph)
  19. register struct tcp *tcph;
  20. struct mbuf *data;
  21. struct pseudo_header *ph;
  22. {
  23. int16 hdrlen;
  24. struct mbuf *bp;
  25. register unsigned char *cp;
  26.  
  27.     hdrlen = TCPLEN;
  28.     if (tcph->optlen > 0 && tcph->optlen <= TCP_MAXOPT)
  29.         hdrlen = (int16) (hdrlen + tcph->optlen);
  30.     else if (tcph->mss != 0)
  31.         hdrlen += MSS_LENGTH;
  32.  
  33.     if ((bp = pushdown (data, hdrlen)) == NULLBUF)    {
  34.         free_p (data);
  35.         return NULLBUF;
  36.     }
  37.     cp = bp->data;
  38.     cp = put16 (cp, tcph->source);
  39.     cp = put16 (cp, tcph->dest);
  40.     cp = put32 (cp, (uint32) tcph->seq);
  41.     cp = put32 (cp, (uint32) tcph->ack);
  42.     *cp++ = (char)(hdrlen << 2);    /* Offset field */
  43.     *cp = 0;
  44.     if (tcph->flags.congest)
  45.         *cp |= 64;
  46.     if (tcph->flags.urg)
  47.         *cp |= 32;
  48.     if (tcph->flags.ack)
  49.         *cp |= 16;
  50.     if (tcph->flags.psh)
  51.         *cp |= 8;
  52.     if (tcph->flags.rst)
  53.         *cp |= 4;
  54.     if (tcph->flags.syn)
  55.         *cp |= 2;
  56.     if (tcph->flags.fin)
  57.         *cp |= 1;
  58.     cp++;
  59.     cp = put16 (cp, tcph->wnd);
  60.     if (ph == NULLHEADER)        /* Use user-supplied checksum */
  61.         cp = put16 (cp, tcph->checksum);
  62.     else {
  63.         /* Zero out checksum field for later recalculation */
  64.         *cp++ = 0;
  65.         *cp++ = 0;
  66.     }
  67.     cp = put16 (cp, tcph->up);
  68.  
  69.     /* Write options, if any */
  70.     if (hdrlen > TCPLEN)    {
  71.         if (tcph->mss != 0)    {
  72.             *cp++ = MSS_KIND;
  73.             *cp++ = MSS_LENGTH;
  74.             cp = put16 (cp, tcph->mss);
  75.         } else
  76.             memcpy (cp, tcph->options, (size_t) (int) tcph->optlen);
  77.     }
  78.     /* Recompute checksum, if requested */
  79.     if (ph != NULLHEADER)
  80.         (void) put16 (&bp->data[16], cksum (ph, bp, ph->length));
  81.  
  82.     return bp;
  83. }
  84.  
  85.  
  86.  
  87. /* Pull TCP header off mbuf */
  88. int
  89. ntohtcp (tcph, bpp)
  90. register struct tcp *tcph;
  91. struct mbuf **bpp;
  92. {
  93. int hdrlen, i, optlen, kind;
  94. register int flags;
  95. char hdrbuf[TCPLEN], *cp;
  96.  
  97.     i = pullup (bpp, (unsigned char *)hdrbuf, TCPLEN);
  98.     /* Note that the results will be garbage if the header is too short.
  99.      * We don't check for this because returned ICMP messages will be
  100.      * truncated, and we at least want to get the port numbers.
  101.      */
  102.     tcph->source = get16 (&hdrbuf[0]);
  103.     tcph->dest = get16 (&hdrbuf[2]);
  104.     tcph->seq = (int32) get32 (&hdrbuf[4]);
  105.     tcph->ack = (int32) get32 (&hdrbuf[8]);
  106.     hdrlen = (hdrbuf[12] & 0xf0) >> 2;
  107.     flags = hdrbuf[13];
  108.     tcph->flags.congest = flags & 64;
  109.     tcph->flags.urg = flags & 32;
  110.     tcph->flags.ack = flags & 16;
  111.     tcph->flags.psh = flags & 8;
  112.     tcph->flags.rst = flags & 4;
  113.     tcph->flags.syn = flags & 2;
  114.     tcph->flags.fin = flags & 1;
  115.     tcph->wnd = get16 (&hdrbuf[14]);
  116.     tcph->checksum = get16 (&hdrbuf[16]);
  117.     tcph->up = get16 (&hdrbuf[18]);
  118.     tcph->mss = 0;
  119.     tcph->optlen = (char) (hdrlen - TCPLEN);
  120.  
  121.     /* Check for option field. Only space for one is allowed, but
  122.      * since there's only one TCP option (MSS) this isn't a problem
  123.      */
  124.     if (i < TCPLEN || hdrlen < TCPLEN)
  125.         return -1;    /* Header smaller than legal minimum */
  126.     if (tcph->optlen == 0)
  127.         return (int)hdrlen;    /* No options, all done */
  128.  
  129.     if ((int16) (int) tcph->optlen > len_p(*bpp))
  130.         /* Remainder too short for options length specified */
  131.         return -1;
  132.  
  133.     (void) pullup (bpp, (unsigned char *)tcph->options, (int16) (int) tcph->optlen);    /* "Can't fail */
  134.     /* Process options */
  135.     for (cp = tcph->options, i = tcph->optlen; i > 0; )    {
  136.         kind = *cp++;
  137.         /* Process single-byte options */
  138.         switch (kind)    {
  139.             case EOL_KIND:    i--;
  140.                     cp++;
  141.                     return (int)hdrlen;    /* End of options list */
  142.             case NOOP_KIND:    i--;
  143.                     cp++;
  144.                     continue;    /* Go look for next option */
  145.             default:    break;
  146.         }
  147.         /* All other options have a length field */
  148.         optlen = uchar(*cp++);
  149.  
  150.         /* Process valid multi-byte options */
  151.         switch (kind)    {
  152.             case MSS_KIND:    if(optlen == MSS_LENGTH)
  153.                         tcph->mss = get16(cp);
  154.                     break;
  155.             default:    break;
  156.         }
  157.         optlen = max(2, optlen);    /* Enforce legal minimum */
  158.         i -= optlen;
  159.         cp += optlen - 2;
  160.     }
  161.     return (int)hdrlen;
  162. }
  163.